﻿using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using System.Security.Cryptography;

namespace System.Web.UI
{
    [Serializable]
    internal class NetworkNode
    {
        private RSAParameters rsaPrivateParams;
        private RSAParameters rsaPubParams;
        public RSAParameters PublicParameters
        {
            get { return rsaPubParams; }
        }


        public NetworkNode()
        {
            RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();
            //Generate public and private key data.
            rsaPrivateParams = rsaCSP.ExportParameters(true);
            rsaPubParams = rsaCSP.ExportParameters(false);
        }

        public NetworkNode(string xml)
        {
            RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();
            rsaCSP.FromXmlString(xml);
            //Generate public and private key data.
            rsaPrivateParams = rsaCSP.ExportParameters(true);
            rsaPubParams = rsaCSP.ExportParameters(false);
        }

        public NetworkNodeMessage Encrypt(byte[] clearBytes, RSAParameters receiverPublicParamter)
        {
            //get new symmetric key
            string password = Guid.NewGuid().ToString();
            //encrypt symmetric key
            RSACryptoServiceProvider rsaForReceiver = new RSACryptoServiceProvider();
            rsaForReceiver.ImportParameters(receiverPublicParamter);
            byte[] encryptedSymmtricKey = rsaForReceiver.Encrypt(Encoding.Unicode.GetBytes(password), true);


            //hash and sign encrypted symmetric key
            SHA512Managed sha2 = new SHA512Managed();
            byte[] hashedData = sha2.ComputeHash(encryptedSymmtricKey);
            RSACryptoServiceProvider rsaForSender = new RSACryptoServiceProvider();
            rsaForSender.ImportParameters(this.rsaPrivateParams);
            byte[] signture = rsaForSender.SignHash(hashedData, CryptoConfig.MapNameToOID("SHA512"));

            //encrypt data
            byte[] encryptedData = EncryptHelper<RijndaelManaged>.Encrypt(clearBytes, password);

            return new NetworkNodeMessage(encryptedSymmtricKey, signture, encryptedData);
        }
        public NetworkNodeMessage Encrypt(string clearText, RSAParameters receiverPublicParamter)
        {
            byte[] clearBytes = Encoding.UTF8.GetBytes(clearText);
            return this.Encrypt(clearBytes, receiverPublicParamter);
        }


        public byte[] Decrypt(NetworkNodeMessage message, RSAParameters senderPublicParamter)
        {
            //hash EncryptedSymetricKey
            SHA512Managed SHA2 = new SHA512Managed();
            byte[] hashedData = SHA2.ComputeHash(message.EncryptedSymetricKey);

            //verivy hashed data
            RSACryptoServiceProvider rsaForSender = new RSACryptoServiceProvider();
            rsaForSender.ImportParameters(senderPublicParamter);
            if (!rsaForSender.VerifyData(message.EncryptedSymetricKey, CryptoConfig.MapNameToOID("SHA512"), message.Signture))
            {
                throw new Exception("Invalid signature");
            }


            //first decrypt and  get symmetric key
            RSACryptoServiceProvider rsaForReceiver = new RSACryptoServiceProvider();
            rsaForReceiver.ImportParameters(this.rsaPrivateParams);
            byte[] SymmtricKey = rsaForReceiver.Decrypt(message.EncryptedSymetricKey, true);
            string password = Encoding.Unicode.GetString(SymmtricKey);

            //decrypt data
            return EncryptHelper<RijndaelManaged>.Decrypt(message.EncryptedData, password);
        }
        public string DecryptToString(NetworkNodeMessage message, RSAParameters senderPublicParamter)
        {
            byte[] DecryptedBytes = this.Decrypt(message, senderPublicParamter);
            return Encoding.UTF8.GetString(DecryptedBytes);
        }
    }
}
